package org.aldar.bquest.util;

import org.aldar.bquest.sound.GameSound;
import org.andengine.entity.sprite.TiledSprite;
import org.andengine.input.touch.TouchEvent;
import org.andengine.opengl.texture.region.ITextureRegion;
import org.andengine.opengl.texture.region.ITiledTextureRegion;
import org.andengine.opengl.texture.region.TiledTextureRegion;
import org.andengine.opengl.vbo.VertexBufferObjectManager;
import org.andengine.util.debug.Debug;

/**
 * User: Daria
 * Date: 9/15/14 11:40 PM
 */
public class CustomButtonSprite extends TiledSprite {

    // ===========================================================
    // Constants
    // ===========================================================

    // ===========================================================
    // Fields
    // ===========================================================

    private final int mStateCount;
    private OnClickListener mOnClickListener;

    private boolean mEnabled = true;
    private State mState;

    private boolean playSound = true;

    public CustomButtonSprite(final float pX, final float pY, final ITextureRegion pNormalTextureRegion, final VertexBufferObjectManager pVertexBufferObjectManager) {
        this(pX, pY, pNormalTextureRegion, pVertexBufferObjectManager, (OnClickListener) null);
    }

    public CustomButtonSprite(final float pX, final float pY, final ITextureRegion pNormalTextureRegion, final VertexBufferObjectManager pVertexBufferObjectManager, final OnClickListener pOnClickListener) {
        this(pX, pY, new TiledTextureRegion(pNormalTextureRegion.getTexture(), pNormalTextureRegion), pVertexBufferObjectManager, pOnClickListener);
    }

    public CustomButtonSprite(final float pX, final float pY, final ITextureRegion pNormalTextureRegion, final ITextureRegion pPressedTextureRegion, final VertexBufferObjectManager pVertexBufferObjectManager) {
        this(pX, pY, pNormalTextureRegion, pPressedTextureRegion, pVertexBufferObjectManager, (OnClickListener) null);
    }

    public CustomButtonSprite(final float pX, final float pY, final ITextureRegion pNormalTextureRegion, final ITextureRegion pPressedTextureRegion, final VertexBufferObjectManager pVertexBufferObjectManager, final OnClickListener pOnClickListener) {
        this(pX, pY, new TiledTextureRegion(pNormalTextureRegion.getTexture(), pNormalTextureRegion, pPressedTextureRegion), pVertexBufferObjectManager, pOnClickListener);
    }

    public CustomButtonSprite(final float pX, final float pY, final ITextureRegion pNormalTextureRegion, final ITextureRegion pPressedTextureRegion, final ITextureRegion pDisabledTextureRegion, final VertexBufferObjectManager pVertexBufferObjectManager) {
        this(pX, pY, pNormalTextureRegion, pPressedTextureRegion, pDisabledTextureRegion, pVertexBufferObjectManager, (OnClickListener) null);
    }

    public CustomButtonSprite(final float pX, final float pY, final ITextureRegion pNormalTextureRegion, final ITextureRegion pPressedTextureRegion, final ITextureRegion pDisabledTextureRegion, final VertexBufferObjectManager pVertexBufferObjectManager, final OnClickListener pOnClickListener) {
        this(pX, pY, new TiledTextureRegion(pNormalTextureRegion.getTexture(), pNormalTextureRegion, pPressedTextureRegion, pDisabledTextureRegion), pVertexBufferObjectManager, pOnClickListener);
    }

    public CustomButtonSprite(final float pX, final float pY, final ITiledTextureRegion pTiledTextureRegion, final VertexBufferObjectManager pVertexBufferObjectManager) {
        this(pX, pY, pTiledTextureRegion, pVertexBufferObjectManager, (OnClickListener) null);
    }


    public CustomButtonSprite(float pX, float pY, ITiledTextureRegion pTiledTextureRegion, VertexBufferObjectManager pVertexBufferObjectManager, OnClickListener pOnClickListener) {
        super(pX, pY, pTiledTextureRegion, pVertexBufferObjectManager);


        this.mOnClickListener = pOnClickListener;
        this.mStateCount = pTiledTextureRegion.getTileCount();

        switch (this.mStateCount) {
            case 1:
                Debug.w("No " + ITextureRegion.class.getSimpleName() + " supplied for " + State.class.getSimpleName() + "." + State.PRESSED + ".");
            case 2:
                Debug.w("No " + ITextureRegion.class.getSimpleName() + " supplied for " + State.class.getSimpleName() + "." + State.DISABLED + ".");
                break;
            case 3:
                break;
            default:
                throw new IllegalArgumentException("The supplied " + ITiledTextureRegion.class.getSimpleName() + " has an unexpected amount of states: '" + this.mStateCount + "'.");
        }
        this.changeState(State.NORMAL);
    }


    @Override
    public boolean contains(final float pX, final float pY) {
        if (!this.isVisible()) {
            return false;
        } else {
            return super.contains(pX, pY);
        }
    }

    @Override
    public boolean onAreaTouched(final TouchEvent pSceneTouchEvent, final float pTouchAreaLocalX, final float pTouchAreaLocalY) {
        if (!this.isEnabled()) {
            this.changeState(State.DISABLED);
        } else if (pSceneTouchEvent.isActionDown()) {
            this.changeState(State.PRESSED);
        } else if (pSceneTouchEvent.isActionCancel() || !this.contains(pSceneTouchEvent.getX(), pSceneTouchEvent.getY())) {
            this.changeState(State.NORMAL);
        } else if (pSceneTouchEvent.isActionUp() && this.mState == State.PRESSED) {
            this.changeState(State.NORMAL);
            GameSound.getCurrentInstance().playButtonClickSound();
            if (this.mOnClickListener != null) {
                this.mOnClickListener.onClick(this, pTouchAreaLocalX, pTouchAreaLocalY);
            }
        } else if (pSceneTouchEvent.isActionMove() &&
                (
                        !this.contains(pSceneTouchEvent.getX() + 5, pSceneTouchEvent.getY()) ||
                                !this.contains(pSceneTouchEvent.getX() - 5, pSceneTouchEvent.getY()) ||
                                !this.contains(pSceneTouchEvent.getX(), pSceneTouchEvent.getY() + 5) ||
                                !this.contains(pSceneTouchEvent.getX(), pSceneTouchEvent.getY() - 5))) {
            this.changeState(State.NORMAL);
        }

        return true;
    }

    public boolean isEnabled() {
        return this.mEnabled;
    }

    public void setEnabled(final boolean pEnabled) {
        this.mEnabled = pEnabled;

        if (this.mEnabled && this.mState == State.DISABLED) {
            this.changeState(State.NORMAL);
        } else if (!this.mEnabled) {
            this.changeState(State.DISABLED);
        }
    }

    public boolean isPressed() {
        return this.mState == State.PRESSED;
    }

    public State getState() {
        return this.mState;
    }

    public void setOnClickListener(final OnClickListener pOnClickListener) {
        this.mOnClickListener = pOnClickListener;
    }


    // ===========================================================
    // Methods
    // ===========================================================

    private void changeState(final State pState) {
        if (pState == this.mState) {
            return;
        }

        this.mState = pState;

        final int stateTiledTextureRegionIndex = this.mState.getTiledTextureRegionIndex();
        if (stateTiledTextureRegionIndex >= this.mStateCount) {
            this.setCurrentTileIndex(0);
            Debug.w(this.getClass().getSimpleName() + " changed its " + State.class.getSimpleName() + " to " + pState.toString() + ", which doesn't have a " + ITextureRegion.class.getSimpleName() + " supplied. Applying default " + ITextureRegion.class.getSimpleName() + ".");
        } else {
            this.setCurrentTileIndex(stateTiledTextureRegionIndex);
        }
    }

    // ===========================================================
    // Inner and Anonymous Classes
    // ===========================================================

    public interface OnClickListener {
        // ===========================================================
        // Constants
        // ===========================================================

        // ===========================================================
        // Methods
        // ===========================================================

        public void onClick(final CustomButtonSprite pButtonSprite, final float pTouchAreaLocalX, final float pTouchAreaLocalY);
    }

    public static enum State {
        // ===========================================================
        // Elements
        // ===========================================================

        NORMAL(0),
        PRESSED(1),
        DISABLED(2);

        // ===========================================================
        // Constants
        // ===========================================================

        // ===========================================================
        // Fields
        // ===========================================================

        private final int mTiledTextureRegionIndex;

        // ===========================================================
        // Constructors
        // ===========================================================

        private State(final int pTiledTextureRegionIndex) {
            this.mTiledTextureRegionIndex = pTiledTextureRegionIndex;
        }

        // ===========================================================
        // Getter & Setter
        // ===========================================================

        public int getTiledTextureRegionIndex() {
            return this.mTiledTextureRegionIndex;
        }

        // ===========================================================
        // Methods for/from SuperClass/Interfaces
        // ===========================================================

        // ===========================================================
        // Methods
        // ===========================================================

        // ===========================================================
        // Inner and Anonymous Classes
        // ===========================================================
    }

    public boolean isPlaySound() {
        return playSound;
    }

    public void setPlaySound(boolean playSound) {
        this.playSound = playSound;
    }
}
